package upool

import "time"

func (tp *TaskPool) Put(task TaskHandler) error {
	if tp.closed {
		return ErrTaskPoolClosed
	}

	tp.Lock()
	tc := tp.capacity
	wc := tp.worker
	tp.Unlock()

	if tc > wc {
		go func() {
			defer func() {
				if rerr := recover(); rerr != nil {
					cfg.RecoverHandler(rerr)
					tp.Lock()
					tp.worker--
					tp.Unlock()
					log.Warn("[UPool] panic a worker")
				}
			}()

			tp.Lock()
			tp.worker++
			tp.Unlock()

			log.Debug("[UPool] started a new worker")

			var (
				duration = time.Duration(cfg.IdleTime) * time.Second
				tk       = time.NewTimer(duration)
			)

		WorkLoop:
			for {
				select {
				case <-tp.ctx.Done():
					log.Debug("[UPool] stopped a worker")
					break WorkLoop
				case <-tk.C:
					log.Debug("[UPool] stopped an idle worker")
					break WorkLoop
				case task, ok := <-tp.taskChan:
					tp.Lock()
					tp.running++
					tp.Unlock()

					if !ok {
						break WorkLoop
					}

					tk.Stop()

					task.Execute()

					tp.Lock()
					tp.running--
					tp.Unlock()

					tk = time.NewTimer(duration)
				}
			}

			tp.Lock()
			tp.worker--
			tp.Unlock()

		}()
	}

	tp.taskChan <- task

	return nil
}
